﻿#include <gl/glew.h>
#include <gl/glut.h>
#include <gl/glu.h>
#include <string>
#include <sstream>
#include <cassert>
#include <iostream>

static const int QUIT_VALUE(99);

GLuint listID;

static void display()
{
  glClear(GL_COLOR_BUFFER_BIT);

  glLoadIdentity();
  glTranslatef(0.f, 0.0f, -4.0f); // 移动成像点到x:0, y:0, z:-4

  glCallList(listID);

  glutSwapBuffers();

  assert(glGetError() == GL_NO_ERROR);
}

static void reshape(int w, int h)
{
  glViewport(0, 0, w, h);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  // arg1: angle of y axis
  // arg2: 纵横比
  // arg3: near plane pos
  // arg4: far plane pos
  gluPerspective(50.0f, (double)w/(double)h, 1.0f, 10.0f);

  glMatrixMode(GL_MODELVIEW);

  assert(glGetError() == GL_NO_ERROR);
}

static void mainMenuCB(int value)
{
  if( value == QUIT_VALUE )
    exit(0);
}

static const GLfloat data[]=
{
  -1.f, -1.f, 0.f,
  1.f, -1.f, 0.f,
  0.f, 1.f, 0.f
};

struct HWBuffer
{
  HWBuffer()
    : _id(0)
  {
    glGenBuffers(1, &_id);

  }

  bool Valid() const { return static_cast<bool>(glIsBuffer(_id)); }

  enum DataType { DT_VERTEX, DT_INDEX };

  void Lunch(DataType type, GLvoid* pData, GLsizeiptr bytes, GLenum usage =GL_STATIC_DRAW)
  {
        GLenum t;
    if(type==DT_VERTEX)
      t = GL_ARRAY_BUFFER;
    else if(type == DT_INDEX)
      t = GL_ELEMENT_ARRAY_BUFFER;

    glBufferData(t, bytes, pData, usage);
  }

  void Apply(DataType type)
  {
    GLenum t;
    if(type==DT_VERTEX)
      t = GL_ARRAY_BUFFER;
    else if(type == DT_INDEX)
      t = GL_ELEMENT_ARRAY_BUFFER;

    glBindBuffer(t, _id);
  }

  ~HWBuffer()
  {
    glDeleteBuffers(1, &_id);
  }
private:
  GLuint _id;
};

inline GLvoid* bufObjPtr(unsigned int idx)
{
  return (GLvoid*)( ((char*)NULL) + idx );
}

HWBuffer* buffer;

static void init()
{
  glDisable(GL_DITHER);

  std::string ver = (const char*) glGetString(GL_VERSION);
  assert(!ver.empty());
  std::istringstream verStream(ver);

  int major, minor;
  char dummySep;
  verStream >> major >> dummySep >> minor;
  const bool useVertexArrays = ( (major>=1) && (minor>=1) );

  buffer = new HWBuffer;

  if(useVertexArrays)
  {
    glEnableClientState(GL_VERTEX_ARRAY);
    //buffer->Lunch(HWBuffer::DT_VERTEX, (void*)data, 3*3*sizeof(GLfloat));
    //buffer->Apply(HWBuffer::DT_VERTEX);
    glVertexPointer(3, GL_FLOAT, 0, data);
  }

  listID = glGenLists(1);
  glNewList(listID, GL_COMPILE);
  if(useVertexArrays)
    glDrawArrays(GL_TRIANGLES, 0, 3);
  else
  {
    glBegin(GL_TRIANGLES);
    glVertex3fv( &data[0] );
    glVertex3fv( &data[3] );
    glVertex3fv( &data[6] );
    glEnd();
  }
  glEndList();

  assert( glGetError() == GL_NO_ERROR );

  glutDisplayFunc(display);
  glutReshapeFunc(reshape);

  int mainMenu = glutCreateMenu(mainMenuCB);
  glutAddMenuEntry("Quit", QUIT_VALUE);
  glutAttachMenu(GLUT_RIGHT_BUTTON);

}

int main(int argc, char* argv[])
{
  glutInit(&argc, argv);

  glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
  glutInitWindowSize(640, 480);
  glutCreateWindow("Simple Queue");

  glewInit();

  init();

  glutMainLoop();

  delete buffer;

  return 0;
}
